/**
* @author TDSoft
*
* La clase CLiente proporciona la ventana mediante la cual
*   se iniciara el cliente RMI. Es necesario para ejecutar las otros subsistemas de la aplicación
*
* @see RemotoInterface, remotoImplementacion
*/
package edu.uoc.tds.pec4.client;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import javax.swing.JOptionPane;
import javax.swing.UIManager;
import java.rmi.RemoteException;


import edu.uoc.tds.pec4.model.Usuario;
import edu.uoc.tds.pec4.common.RemotoInterface;
import edu.uoc.tds.pec4.exception.CampoVacioException;
import edu.uoc.tds.pec4.exception.UsuarioNoValidadoException;
import edu.uoc.tds.pec4.i18n.GestorIdiomas;
import edu.uoc.tds.pec4.swingx.PantallaMenuPrincipal;

public class Cliente extends javax.swing.JFrame {
    /** Atributo referido a la instancia del servidor remoto. */
    private RemotoInterface remoto;
    /** Atributo referido al la URL del servidor remoto. */
    private final String url = new String("rmi://localhost/eOlympics");
    /** Indica si la conexión al servidor remoto ha sido realizada o no. */
    private boolean conexionRealizadaRMI = false;
    /** Indica si la conexión a la BBDD ha sido realizada o no. */
    private boolean conexionRealizadaBBDD = false;

    /**
     * Constructor sin parámetros de la clase Cliente.
     * Crea una instancia de Cliente.
     * {pre: no hay parámetros}
     * {post: devuelve una instancia de la clase Cliente}
     */
    public Cliente() {
        try {
            myInitComponents();
             //Se inicializa el control de mensajes
            if (!GestorIdiomas.setDefaultLanguage("i18n/messages")){
                //Al no encontrarse el fichero añadimos el texto directamente. Es el único caso.
                JOptionPane.showMessageDialog(this, "No se ha encontrado el fichero de mensajes", "error", JOptionPane.ERROR_MESSAGE);
            }
            else{
                initComponents();
            }
        }
        /** Capturamos excepción de carácter general*/
        catch (Exception exc) {
            //Error inesperado
            JOptionPane.showMessageDialog(this, GestorIdiomas.getMessage("error.general"), GestorIdiomas.getMessage("error"), JOptionPane.ERROR_MESSAGE);
        }
    }
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jlblUsuarioConectado = new javax.swing.JLabel();
        jtxtUsuarioConectado = new javax.swing.JTextField();
        jbtnConectarServidor = new javax.swing.JButton();
        jlblPassword = new javax.swing.JLabel();
        jPasswordUsuario = new javax.swing.JPasswordField();
        jbtnCancelarServidor = new javax.swing.JButton();
        jlblInfoCliente = new javax.swing.JLabel();
        jlblImagen = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("i18n/messages"); // NOI18N
        setTitle(bundle.getString("Cliente.title")); // NOI18N

        jlblUsuarioConectado.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
        jlblUsuarioConectado.setText(bundle.getString("jlblUsuarioConectado.text")); // NOI18N
        jlblUsuarioConectado.setToolTipText("");

        jtxtUsuarioConectado.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
        jtxtUsuarioConectado.setToolTipText("");

        jbtnConectarServidor.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N
        jbtnConectarServidor.setText(bundle.getString("jbtnConectarServidor.text")); // NOI18N
        jbtnConectarServidor.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jbtnConectarServidorActionPerformed(evt);
            }
        });

        jlblPassword.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
        jlblPassword.setText(bundle.getString("jlblPassword.text")); // NOI18N

        jbtnCancelarServidor.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N
        jbtnCancelarServidor.setText(bundle.getString("jbtnCancelarServidor.text")); // NOI18N
        jbtnCancelarServidor.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jbtnCancelarServidorActionPerformed(evt);
            }
        });

        jlblInfoCliente.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N
        jlblInfoCliente.setText(bundle.getString("jlblInfoCliente.text")); // NOI18N
        jlblInfoCliente.setFocusable(false);
        jlblInfoCliente.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);

        jlblImagen.setIcon(new javax.swing.ImageIcon(getClass().getResource("/edu/uoc/tds/pec4/images/logo eOlympics2.jpg"))); // NOI18N
        jlblImagen.setToolTipText("");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jlblImagen)
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jlblInfoCliente, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(jbtnConectarServidor, javax.swing.GroupLayout.PREFERRED_SIZE, 125, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(jbtnCancelarServidor, javax.swing.GroupLayout.PREFERRED_SIZE, 126, javax.swing.GroupLayout.PREFERRED_SIZE))
                            .addGroup(layout.createSequentialGroup()
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addComponent(jlblUsuarioConectado, javax.swing.GroupLayout.PREFERRED_SIZE, 65, javax.swing.GroupLayout.PREFERRED_SIZE)
                                    .addComponent(jlblPassword))
                                .addGap(18, 18, 18)
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addComponent(jtxtUsuarioConectado, javax.swing.GroupLayout.PREFERRED_SIZE, 274, javax.swing.GroupLayout.PREFERRED_SIZE)
                                    .addComponent(jPasswordUsuario, javax.swing.GroupLayout.PREFERRED_SIZE, 274, javax.swing.GroupLayout.PREFERRED_SIZE))))
                        .addGap(0, 0, Short.MAX_VALUE)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jlblInfoCliente)
                        .addGap(31, 31, 31)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(jlblUsuarioConectado)
                            .addComponent(jtxtUsuarioConectado, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addGap(18, 18, 18)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(jPasswordUsuario, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(jlblPassword, javax.swing.GroupLayout.PREFERRED_SIZE, 15, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(jbtnConectarServidor)
                            .addComponent(jbtnCancelarServidor)))
                    .addComponent(jlblImagen, javax.swing.GroupLayout.PREFERRED_SIZE, 179, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        setBounds((screenSize.width-720)/2, (screenSize.height-239)/2, 720, 239);
    }// </editor-fold>//GEN-END:initComponents

    /**
     * Método para iniciar los componentes que forman parte de la clase. Se asignan valores a sus atributos
     * {pre: la clase ha de estar instanciada previamente}
     * {post: permite que el atributo setVIsible se pueda establecer a TRUE}
     */
    private void myInitComponents(){
        setLookAndFeelWIndows();
    }

    /**
     * Método para establecer la apariencia de la venta en función del sistema operativo, utilizando la apariencia predetermianda del sistema operativo
     * {pre: se ejecuta en el momento en que se instancia la clase}
     * {post: no devuelve ningún tipo de valor aunque se controla la posible presencia de excepciones}
     */
    private void setLookAndFeelWIndows(){
	try{
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
	}
        /** Capturamos excepción de carácter general*/
        catch(Exception e){
            JOptionPane.showMessageDialog(this, GestorIdiomas.getMessage("error.lookAndFeel"), GestorIdiomas.getMessage("error"), JOptionPane.ERROR_MESSAGE);
	}
    }

    /**
     * Método que controla la acción sobre el componente jbtnConectar
     * {pre: la clase ha de estar instanciada previamente}
     * {post: realiza la conexión al servidor RMI y a la BBDD}
     * @param evt hace referencia a la instancia de ActionEvent que origina la ejecución del método
     */
    private void jbtnConectarServidorActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jbtnConectarServidorActionPerformed
        
        //Cada vez que se pulse conectar hay que intentar conectarse al servidor rmi por si se hubiese desconectado
        //entre medias, ya que el usuario ha podido confundirse al logearse y puede intentarlo varias veces.
        this.conectarRMI();
        if(this.conexionRealizadaRMI){
            if (!this.conexionRealizadaBBDD)
                this.conectarBBDD();
        }
    }//GEN-LAST:event_jbtnConectarServidorActionPerformed

    /**
     * Método que controla la acción sobre el componente jbtnCancelar
     * {pre: la clase ha de estar instanciada previamente}
     * {post: realiza la desconexión de la BBDD}
     * @param evt hace referencia a la instancia de ActionEvent que origina la ejecución del método
     */
    private void jbtnCancelarServidorActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jbtnCancelarServidorActionPerformed
        Cancelar();
    }//GEN-LAST:event_jbtnCancelarServidorActionPerformed

    /**
     * Método que permite la conexión a la BBDD
     * {pre: la clase ha de estar instanciada previamente}
     * {post: realiza la conexión al servidor de la BBDD y valida al usuario si existe en el sistema}
     */
    private void conectarBBDD(){
        String login;
        char[] aClave;
        String mensaje = GestorIdiomas.getMessage("error.campo.vacio");
        try{
            //Obtenemos los datos introducidos por el usuario
            login = this.jtxtUsuarioConectado.getText();
            aClave = this.jPasswordUsuario.getPassword();

            //Si no se introduce el campo se lanza la excepción correspondiente a ese caso
            if(login.equals("")){
                throw new CampoVacioException(String.format(mensaje,GestorIdiomas.getMessage("cliente.campo.login")));
            }
            
            //Si no se introduce el campo se lanza la excepción correspondiente a ese caso
            if(aClave.length == 0){
                throw new CampoVacioException(String.format(mensaje,GestorIdiomas.getMessage("cliente.campo.password")));
            }

            //Si se realiza la conexión a la BBDD pasamos a validar si el usuario existe en el sistema
            //a partir de su usuario y contraseña
            if (this.remoto.conectaBBDD()){
                //Se llama al método remoto que valida al usuario
                Usuario usuario = this.remoto.validarUsuario(login,String.valueOf(aClave));
                //Si el usuario está validado
                if (usuario.getValidado()){
                    //Si el usuario no está dado de baja
                    if (usuario.getFecha_baja() == null)
                    {
                        //Abrimos la pantalla de menú principal
                        this.conexionRealizadaBBDD = true;
                        this.setVisible(false);
                        this.AbrirPantallaMenuPrincipal(usuario);
                    }else{
                        //Se muestra mensaje de que ese usuario ya está dado de baja
                        JOptionPane.showMessageDialog(this, GestorIdiomas.getMessage("info.usuario.baja"), GestorIdiomas.getMessage("informacion"), JOptionPane.INFORMATION_MESSAGE);
                    }
                }else{
                    //Se muestra mensaje de que el usuario no existe en el sistema
                    throw new UsuarioNoValidadoException(GestorIdiomas.getMessage("error.usuario.no.validado"));
                } 
            }else{
                //Se muestra mensaje de que no se podido establecer la conexión a la BBDD
                JOptionPane.showMessageDialog(this, GestorIdiomas.getMessage("warning.cliente.conexionBBDD.norealizada"), GestorIdiomas.getMessage("aviso"), JOptionPane.WARNING_MESSAGE);
            }
        }
        /**Capturamos el error en caso de que no se asigne ningún valor al login*/
        catch(CampoVacioException exc){
            JOptionPane.showMessageDialog(this, exc.getMessage(), GestorIdiomas.getMessage("aviso"), JOptionPane.WARNING_MESSAGE);
        }
        /**Capturamos el error en caso de que el usuario no esté validado*/
        catch(UsuarioNoValidadoException exc){
            JOptionPane.showMessageDialog(this, exc.getMessage(), GestorIdiomas.getMessage("aviso"), JOptionPane.WARNING_MESSAGE);
        }
        /**Capturamos el error remoto*/
        catch(RemoteException exc){
            JOptionPane.showMessageDialog(this, exc.detail, GestorIdiomas.getMessage("error"), JOptionPane.ERROR_MESSAGE);
        }
        /** Capturamos excepción de carácter general*/
        catch(Exception exc){
            JOptionPane.showMessageDialog(this, GestorIdiomas.getMessage("error.general"), GestorIdiomas.getMessage("error"), JOptionPane.ERROR_MESSAGE);
        } 
    }

    /**
     * Método que permite la conexión al servidor RMI
     * {pre: la clase ha de estar instanciada previamente}
     * {post: realiza la conexión al servidor RMI}
     */
    private void conectarRMI() {
        try {
            if (this.conexionRealizadaRMI){
                //Si previamente ya había conexión lo volvemos a intentar por si se hubiese caido el 
                //servidor en los intentos de conexión del usuario.
                //Volvemos a inicializar la variable a false por si no pudiésemos conectarnos
                //Si nos conectamos, no volvemos a mostrar el mensaje
                this.conexionRealizadaRMI = false;
                this.remoto = (RemotoInterface) Naming.lookup(this.url);
                this.conexionRealizadaRMI = true;
            }else{
                //Si previamente no había conexión nos conectamos y mostramos el mensaje la primera vez sólo
                this.remoto = (RemotoInterface) Naming.lookup(this.url);
                this.conexionRealizadaRMI = true;
                JOptionPane.showMessageDialog(this, GestorIdiomas.getMessage("informacion.cliente.conexionRMI.realizada"), GestorIdiomas.getMessage("informacion"), JOptionPane.INFORMATION_MESSAGE);
            }
        }
        /** Capturamos excepción asociada a errores en el la asociaciÓn de un serviCio RMI*/
        catch (NotBoundException exc) {
            JOptionPane.showMessageDialog(this, GestorIdiomas.getMessage("info.servidor.no.iniciado"), GestorIdiomas.getMessage("error"), JOptionPane.ERROR_MESSAGE);
        }
        /** Capturamos excepción asociada a la creación de la URL del servidor RMI*/
        catch (MalformedURLException exc) {
            JOptionPane.showMessageDialog(this, GestorIdiomas.getMessage("error.malformed.text"), GestorIdiomas.getMessage("error"), JOptionPane.ERROR_MESSAGE);
        }
        /** Capturamos excepción de carácter general*/
        catch (Exception exc) {
            JOptionPane.showMessageDialog(this, GestorIdiomas.getMessage("error.general"), GestorIdiomas.getMessage("error"), JOptionPane.ERROR_MESSAGE);
        }
    }

    /**
     * Método que permite instanciar la clase frontera que permite conectarse a las funcionalidades de los distintos subsistemas
     * {pre: la clase ha de estar instanciada previamente}
     * {post: abre la pantalla que contiene el menú principal para conectarse a los distintos subsistemas}
     * @param usuarioConectado hace referencia a la instancia de Usuario conectado y validado al aplicativo
     */
    private void AbrirPantallaMenuPrincipal(Usuario usuarioConectado) {
        try {
            PantallaMenuPrincipal pantallaMenuPrincipal = new PantallaMenuPrincipal(usuarioConectado,this.remoto);
            pantallaMenuPrincipal.setVisible(true);
        }
        /** Capturamos excepción de carácter general*/
        catch (Exception exc) {
            JOptionPane.showMessageDialog(this, GestorIdiomas.getMessage("error.general"), GestorIdiomas.getMessage("error"), JOptionPane.ERROR_MESSAGE);
        }
    }

    /**
     * Método que se encarga de realizar las desconexión a la BBDD
     * {pre: la clase ha de estar instanciada previamente}
     * {post: desconexión de la BBDD}
     */
    private void Cancelar(){
        try{
            //Si hay conexión RMI
            if(this.conexionRealizadaRMI){
                //Si hay conexión a BBDD
                if (this.conexionRealizadaBBDD){
                    //Realizamos la desconexión BBDD
                    this.remoto.desconectaBBDD();
                    JOptionPane.showMessageDialog(this,GestorIdiomas.getMessage("info.desconexionrealizada"), GestorIdiomas.getMessage("informacion"), JOptionPane.INFORMATION_MESSAGE);
                }
            }
        } 
        catch (RemoteException exc) {
            /** Capturamos excepción de la invocación remota*/
            JOptionPane.showMessageDialog(this, exc.detail, GestorIdiomas.getMessage("error"), JOptionPane.ERROR_MESSAGE);
        }
        catch (Exception exc) {
            /** Capturamos excepción de caracter general*/
            JOptionPane.showMessageDialog(this, GestorIdiomas.getMessage("error.general"), GestorIdiomas.getMessage("error"), JOptionPane.ERROR_MESSAGE);
        }
        finally{
            this.setVisible(false);
            System.exit(0);
        }
    }
    
    /**
     * Método main de la clase
     * {pre: }
     * {post: se instancia la clase}
     * @param args[] es un arreglo de parámetros que recibe la clase para parametrizar sus instanciación
     */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new Cliente().setVisible(true);
            }
        });
    }
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JPasswordField jPasswordUsuario;
    private javax.swing.JButton jbtnCancelarServidor;
    private javax.swing.JButton jbtnConectarServidor;
    private javax.swing.JLabel jlblImagen;
    private javax.swing.JLabel jlblInfoCliente;
    private javax.swing.JLabel jlblPassword;
    private javax.swing.JLabel jlblUsuarioConectado;
    private javax.swing.JTextField jtxtUsuarioConectado;
    // End of variables declaration//GEN-END:variables

}
